package com.ds.robot.assistant.service.yunxiao;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.aliyun.sdk.service.devops20210625.models.ListWorkitemsRequest;
import com.aliyun.sdk.service.devops20210625.models.ListWorkitemsResponse;
import com.aliyun.sdk.service.devops20210625.models.ListWorkitemsResponseBody;
import com.ds.robot.assistant.entity.BugInfo;
import com.ds.robot.assistant.enums.WorkItemCategoryEnum;
import com.ds.robot.assistant.service.BugInfoService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.apache.poi.util.StringUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 作用：
 *
 * @author WeiShaoying
 * 
 */
@Component
@Slf4j
@SuppressWarnings("ALL")
public class YunXiaoBugSyncClient extends YunXiaoBase {

    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    @Resource
    private BugInfoService bugInfoService;

    @Value("${sync.month:5}")
    private Integer month;

    public void doSyncBug() {
        if (Objects.isNull(userCache)) {
            throw new RuntimeException("userCache is null");
        }
        if (Objects.isNull(projectCache)) {
            throw new RuntimeException("projectCache is null");
        }
        log.info("项目数量={}", getProjectMap().size());

        for (Map.Entry<String, String> entry : getProjectMap().entrySet()) {
            String nextToken = null;
            int total = 0;
            do {
                ListWorkitemsRequest listWorkitemsRequest = ListWorkitemsRequest.builder()
                        .organizationId(ORGANIZATION_ID)
                        .spaceType(STR_PROJECT)
                        .spaceIdentifier(entry.getKey())
                        .category(WorkItemCategoryEnum.Bug.name())
                        .maxResults(MAX_RESULTS)
                        .nextToken(nextToken)
                        // .conditions("{\"conditionGroups\":[[{\"fieldIdentifier\":\"status\",\"operator\":\"CONTAINS\",\"value\":[\"30\",\"100005\",\"28\",\"100010\",\"32\",\"142838\"],\"toValue\":null,\"className\":\"status\",\"format\":\"list\"}]]}")
                        // Request-level configuration rewrite, can set Http request parameters, etc.
                        // .requestConfiguration(RequestConfiguration.create().setHttpHeaders(new HttpHeaders()))
                        .build();
                CompletableFuture<ListWorkitemsResponse> responseFuture = asyncClient.listWorkitems(listWorkitemsRequest);
                ListWorkitemsResponse response = responseFuture.join();

                if (response == null || response.getBody() == null) {
                    log.error("Response or body is null");
                    break;
                }
                List<ListWorkitemsResponseBody.Workitems> list = response.getBody().getWorkitems();
                if (CollectionUtils.isEmpty(list)) {
                    break;
                }
                total += list.size();
                nextToken = response.getBody().getNextToken();
                log.debug("nextToken={}", nextToken);

                List<BugInfo> bugInfoList = list.stream().map(item -> {
                    BugInfo bugInfo = new BugInfo();
                    bugInfo.setIdentifier(item.getIdentifier());
                    bugInfo.setSubject(item.getSubject());
                    bugInfo.setStatusIdentifier(item.getStatusIdentifier());
                    bugInfo.setStatus(item.getStatus());
                    bugInfo.setAssignedTo(item.getAssignedTo());
                    bugInfo.setAssignedToName(getNameFromCache(bugInfo.getAssignedTo()));
                    bugInfo.setCreator(item.getCreator());
                    bugInfo.setCreatorName(getNameFromCache(bugInfo.getCreator()));
                    bugInfo.setGmtCreate(item.getGmtCreate());
                    bugInfo.setGmtModified(item.getGmtModified());
                    bugInfo.setFinishTime(item.getFinishTime());
                    bugInfo.setSpaceId(item.getSpaceIdentifier());
                    bugInfo.setSpaceName(item.getSpaceName());
                    bugInfo.setCreatedAt(new Date());
                    bugInfo.setUpdatedAt(new Date());
                    return bugInfo;
                }).collect(Collectors.toList());

                boolean saved = bugInfoService.saveBatch(bugInfoList);
                log.debug("批量保存saved = {}", saved);

            } while (StrUtil.isNotBlank(nextToken));

            log.info("{}：缺陷数量={}", entry.getValue(), total);
        }
    }

    private String getNameFromCache(String key) {
        String value = userCache.getIfPresent(key);
        if (StringUtil.isNotBlank(value)) {
            return value;
        }
        return USER_MAP.getOrDefault(key, null);
    }

    public void doUpdateBug() {
        if (Objects.isNull(userCache)) {
            throw new RuntimeException("userCache is null");
        }
        if (Objects.isNull(projectCache)) {
            throw new RuntimeException("projectCache is null");
        }
        log.info("查询项目数量={}", getProjectMap().size());

        String condition = "{\"conditionGroups\":[[{\"fieldIdentifier\":\"gmtModified\",\"operator\":\"BETWEEN\",\"value\":[\"%s\"],\"toValue\":\"%s\",\"className\":\"dateTime\",\"format\":\"input\"}]]}";
        LocalDateTime endTime = LocalDateTime.now();
        LocalDateTime beginTime = endTime.minusMonths(month);
        String conditionStr = String.format(condition, FORMATTER.format(beginTime), FORMATTER.format(endTime));
        log.debug("条件={}", conditionStr);

        for (Map.Entry<String, String> entry : getProjectMap().entrySet()) {
            String nextToken = null;
            List<BugInfo> yxBugList = Lists.newArrayList();
            do {
                ListWorkitemsRequest listWorkitemsRequest = ListWorkitemsRequest.builder()
                        .organizationId(ORGANIZATION_ID)
                        .spaceType(STR_PROJECT)
                        .spaceIdentifier(entry.getKey())
                        .category(WorkItemCategoryEnum.Bug.name())
                        .maxResults(MAX_RESULTS)
                        .nextToken(nextToken)
                        .conditions(conditionStr)
                        // .requestConfiguration(RequestConfiguration.create().setHttpHeaders(new HttpHeaders()))
                        .build();
                CompletableFuture<ListWorkitemsResponse> responseFuture = asyncClient.listWorkitems(listWorkitemsRequest);
                ListWorkitemsResponse response = responseFuture.join();

                if (response == null || response.getBody() == null) {
                    log.error("Response or body is null");
                    break;
                }
                List<ListWorkitemsResponseBody.Workitems> list = response.getBody().getWorkitems();
                if (CollectionUtils.isEmpty(list)) {
                    break;
                }
                // log.info("缺陷信息={}", JSON.toJSONString(list));
                nextToken = response.getBody().getNextToken();
                log.debug("nextToken = {}", nextToken);

                List<BugInfo> tempList = list.stream().map(item -> {
                    BugInfo bugInfo = new BugInfo();
                    bugInfo.setIdentifier(item.getIdentifier());
                    bugInfo.setSubject(item.getSubject());
                    bugInfo.setStatusIdentifier(item.getStatusIdentifier());
                    bugInfo.setStatus(item.getStatus());
                    bugInfo.setAssignedTo(item.getAssignedTo());
                    bugInfo.setAssignedToName(getNameFromCache(bugInfo.getAssignedTo()));
                    bugInfo.setCreator(item.getCreator());
                    bugInfo.setCreatorName(getNameFromCache(bugInfo.getCreator()));
                    bugInfo.setGmtCreate(item.getGmtCreate());
                    bugInfo.setGmtModified(item.getGmtModified());
                    bugInfo.setFinishTime(item.getFinishTime());
                    bugInfo.setSpaceId(item.getSpaceIdentifier());
                    bugInfo.setSpaceName(item.getSpaceName());
                    bugInfo.setCreatedAt(new Date());
                    bugInfo.setUpdatedAt(new Date());
                    return bugInfo;
                }).collect(Collectors.toList());

                if (!CollectionUtils.isEmpty(tempList)) {
                    yxBugList.addAll(tempList);
                }
            } while (StrUtil.isNotBlank(nextToken));

            // 查询最近N个月的数据
            List<BugInfo> dbBugList = bugInfoService.lambdaQuery().eq(BugInfo::getSpaceId, entry.getKey())
                    .between(BugInfo::getGmtModified, getMillis(beginTime), getMillis(endTime))
                    .list();
            if (CollectionUtils.isEmpty(dbBugList)) {
                dbBugList = Lists.newArrayList();
            }
            if (CollectionUtils.isEmpty(yxBugList) && CollectionUtils.isEmpty(dbBugList)) {
                continue;
            }
            // 转成Map
            Map<String, BugInfo> dbBugMap = dbBugList.stream().collect(Collectors.toMap(BugInfo::getIdentifier, Function.identity()));
            Map<String, BugInfo> yxBugMap = yxBugList.stream().collect(Collectors.toMap(BugInfo::getIdentifier, Function.identity()));

            List<BugInfo> newBugList = Lists.newArrayList();
            List<BugInfo> updateBugList = Lists.newArrayList();
            List<String> deleteBugList = Lists.newArrayList();
            for (BugInfo bug : yxBugList) {
                if (dbBugMap.containsKey(bug.getIdentifier())) {
                    if (dbBugMap.get(bug.getIdentifier()).getGmtModified() < bug.getGmtModified()) {
                        bug.setId(dbBugMap.get(bug.getIdentifier()).getId());
                        bug.setCreatedAt(null);
                        // bug.setUpdatedAt(null);
                        updateBugList.add(bug);
                    }
                } else {
                    newBugList.add(bug);
                }
            }
            // 计算删除的Bug
            for (BugInfo bugInfo : dbBugList) {
                if (!yxBugMap.containsKey(bugInfo.getIdentifier())) {
                    deleteBugList.add(bugInfo.getIdentifier());
                }
            }
            log.info("[{}], 新增数量={}，更新数量={}，删除数量={}", entry.getValue(), newBugList.size(), updateBugList.size(), deleteBugList.size());
            if (!newBugList.isEmpty()) {
                log.info("新增的Bug={}", JSON.toJSONString(newBugList));
                // MP已经自动把创建和更新时间戳设置为当前时间，其实数据库会自动填充，两种方式都可以
                bugInfoService.saveBatch(newBugList);
            }
            if (!updateBugList.isEmpty()) {
                log.info("更新的Bug={}", JSON.toJSONString(updateBugList));
                // 把不想更新的字段设置为null
                bugInfoService.updateBatchById(updateBugList);
            }
            if (!deleteBugList.isEmpty()) {
                log.info("删除的Bug={}", JSON.toJSONString(deleteBugList));
                bugInfoService.lambdaUpdate().in(BugInfo::getIdentifier, deleteBugList).remove();
            }
        }
    }

    public long getMillis(LocalDateTime localDateTime) {
        // return localDateTime.atStartOfDay(ZoneId.systemDefault()).toInstant().toEpochMilli();
        return localDateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
    }

    public static void main(String[] args) {
        ZoneId defaultZoneId = ZoneId.systemDefault();
        System.out.println("System default time zone: " + defaultZoneId);
    }

}
